#ifndef NET_MANAGER_H
#define NET_MANAGER_H
#include <stddef.h>
#include <cm/struct/cm_fifo.h>

#ifdef __cplusplus
extern "C" {
#endif

struct net_manager;
struct net_session;
struct net_server;

/* @brief	调用回调函数时，用来传递事件类型 */
enum SESSION_EVENT {
	SESSION_E_NEW, /* 一个新会话的建立，主要用于服务器 */
	SESSION_E_BROKEN, /* 会话连接断开，只有通过netm_addclient添加的会话能收到该事件 */
	SESSION_E_DATA /* 有新的数据到来 */
};

/* @brief	发送数据时返回值 */
enum SESSION_SEND_RESULT {
	SSR_SUCCESS, SSR_TIMEOUT, SSR_FULL, SSR_ERROR
};

#define NETM_O_NONE (0)
#define NETM_O_KEEPALIVE (1)

/*
 * @brief	定义函数指针类型，指向某个用来处理会话中数据的函数，
 * @param	e: 事件
 * 		session: 指向产生事件的会话
 * 		data: 如果事件是 SESSION_E_DATA，则data是收到的数据，否则data是NULL
 * @return 	无
 */
typedef void (*session_proc)(enum SESSION_EVENT e, struct net_session *session,
		struct cm_fifo *data);

/*
 * @brief	创建一个net manager, 用来添加网络端（服务端或客户端）
 * 		1、负责接收网络数据，包括接收新的连接(accept)
 * 		2、调用会话和服务器中关联的回调函数
 * @param	flag：选项，详见各个选项的定义
 * @return	成功则返回指向管理者的指针,失败则返回NULL
 */
struct net_manager* netm_create(int flag);

/*
 * @brief	销毁一个net manager, 关闭其中所有的连接及服务器
 * @return	*manager将被设置为NULL，因为它不能再使用
 */
void netm_destroy(struct net_manager **manager);

/*
 * @brief	向网络管理者m中添加一个服务器
 * @param	ip, port: 指定服务器监听的地址和端口,ip设置NULL则监听所有地址
 * @param	rsize, wsize: 指定服务器将为每一个连接上来的会话创建多大的接收和发送缓存
 * @param	proc: 指定当服务器接收到数据时，使用哪个函数来处理
 * @return	服务器对象，失败则返回NULL
 */
struct net_server* netm_addserver(struct net_manager *m, const char *ip,
		unsigned short port, size_t rsize, size_t wsize,
		session_proc proc);

/*
 * @brief	向m中添加一个客户端连接
 * @param	ip,port: 指定对端服务的地址和端口
 * @param	rsize, wsize: 指定该会话需要创建多大的接收和发送缓存，发送缓存可以为0
 * @param	proc: 指定当接收到数据时，使用哪个函数来处理数据
 * @return	建立连接后的会话
 */
struct net_session* netm_addclient(struct net_manager *m, const char *ip,
		unsigned short port, size_t rsize, size_t wsize,
		session_proc proc);

/*
 * @brief	关闭一个服务端，将它从manager中移除，同时关闭其中所有会话
 * @return	关闭失败返回-1（可能服务器正在处理数据），成功返回0
 */
int netm_closeserver(struct net_manager *manager, struct net_server **server);

/*
 * @brief	关闭一个客户端，将它从manager中移除
 * @return	关闭失败返回-1（可能正在处理数据），成功返回0
 */
int netm_closesession(struct net_manager *manager,
		struct net_session **session);

/*
 * @brief	将数据通过session发送出去
 * @param	session：一个会话的指针，一般是通过netm_addclient或在回调函数session_proc中获得
 * 		data，size：要发送的数据位置和大小
 * 		timeout：超时设置，0表示不设置超时，可以永远阻塞。 >0的值设置超时时间，单位毫秒(千分之一秒)
 * @return	发送结果状态, SSR_SUCCESS表示全部发送完成，SSR_TIMEOUT表示此次发送超时
 * 		SSR_FULL表示此次无法写入缓存，SSR_ERROR表示出错，应该立即关闭session
 */
enum SESSION_SEND_RESULT session_send(struct net_session *session,
		const char *data, size_t size, int timeout);

/*
 * @brief	将数据发送给服务端中的所有会话
 * @param	server：一个服务端的指针，一般是通过netm_addserver获得
 * 		data，size：要发送的数据位置和大小
 * 		timeout：超时设置，0表示不设置超时，可以永远阻塞。 >0的值设置超时时间，单位毫秒(千分之一秒)
 * @return	>= 0 表示一共发给了多少个客户端会话, < 0 表示出错
 */
int server_send(struct net_server *server, const char *data, size_t size,
		int timeout);

#ifdef __cplusplus
}
#endif

#endif
